function [lpostmin,xmax,exitflag,output]=...
    estima_fminsearch(x0,parvec,parposest,partrmat_est,funcmod,Y,trainvec,prpar,prss,solveopt,addsol,ssposest,estimopt)
% ======================================================================
% ESTIMA_FMINSEARCH.M
%
% Uses FMINCON optimization routine 
% Function underlying minization is identical to LMJ_POSTOPTIM.m and is
% included as a nested function. Only difference is that the parameter does 
% not go through the transformation matrix since the bounds are directly applied to the optimization 
% procedure using BOUNDS loaded from prior. 
% Hence X0 is an unstransformed starting value 
% format.  
%
% Input 
% ------
% Note:     Input PRPAR.LBND and PRPAR.UBND is truncated inside code 
% ESTIMOPT  Has all the settings for the optimization  
% Output 
% ------
% XMIN      in MIN  space for compatibility with GENSYSOUTPUT 
% XMODEL    in MODEL space  
% LPOSTMIN  stil *(-1) 
% Using OUTPUT, will display end message in a DIARY file created in the
% output subdirectory 
% 
% Alejandro Justiniano  January 11 2008 
% 1/13/09 Added LBND and UBND in priordens s.t. can work with the truncated
% BETA 
% =======================================================================
clear x lpostd; 
if any(imag(x0)~=0);error('Initial guess X0 cannot be imaginary');end
if size(partrmat_est,1)~=length(x0);
    error('Rows in PARTRMAT_EST do not coincide with X0')
end
% Truncate bounds 
% ========================================================================
% Define the bounds for the optimization to ensure compatibility with
% INDMAT. Also check suggested starting point is within bounds, else adjust
% BOUNDS should NOT be truncated 
% ========================================================================
offset=0; 
bounds=[prpar.lbnd(parposest)+offset prpar.ubnd(parposest)-offset]; 
check1=find(x0 < bounds(:,1));
check2=find(x0 > bounds(:,2)); 
if ~isempty(check1) 
    check1_disc=abs(x0(check1)-prpar.lbnd(check1)); 
    if max(check1_disc) > 0.01;error('Starting value is below lower bound');end
    x0(check1)=x0(check1)+check1_disc+offset; 
end 
if ~isempty(check2) 
    check2_disc=abs(x0(check2)-prpar.ubnd(check2)); 
    if max(check2_disc) > 0.01;
        dispaj('Positions ',check2(:),' above upper bound')
        error('Starting value is above upper bound')
    end
    x0(check2)=x0(check2)-check2_disc-offset;
end 
clear check* offset; 
% ========================================================================
% Begin Optimization  
% ========================================================================
x0min=mod2min(x0,partrmat_est); 
tic;
[xmin,lpostmin,exitflag,output]=fminsearch(@lmj_postoptimsub,x0min,estimopt);
xmax=min2mod(xmin,partrmat_est); 
% ============================================
%           NESTED FUNCTION
% ============================================ 
    function lpostd=lmj_postoptimsub(x)
        lpostd=1e20;
        
        [x,flag_continue]=check_min(x,partrmat_est);
        parvec(parposest)=x; 
        if flag_continue==0;
            return
        end
        % 1. Log Likelihood, with normalizing constant included
        switch addsol.flag_mixfreq
            case 0
                [lht,ssvec,flag_ok] = lmj_likel(x, parvec, parposest, funcmod, Y, trainvec,solveopt, addsol);
            case 1
                if addsol.flag_gtv == 1
                    [lht, ssvec,flag_ok] = lmj_likel_tagtv(x, parvec, parposest, funcmod, Y, trainvec, solveopt, addsol);
                else
                    [lht, ssvec,flag_ok] = lmj_likel_tagin(x, parvec, parposest, funcmod, Y, trainvec, solveopt, addsol);
                end
        end
        if flag_ok==0;
            return
        end
        
        % 2. Prior for the parameters
        lpriord=sum(priordens(parvec,prpar.prior,prpar.alphap,prpar.betap,prpar.lbnd,prpar.ubnd));
        if isinf(abs(lpriord))==1;disp('Prior is INF');return;end
        
        % 3. Prior for the SS
        if ~isempty(ssposest)
            lpriord_ss = sum(priordens(ssvec(ssposest), prss.prior, prss.alphap, prss.betap, prss.lbnd, prss.ubnd));
        else
            lpriord_ss=0;
        end
        
        lpostd=-(lpriord+lpriord_ss+lht);
        %disp(['LPOSTD=',num2str(lpostd)]);
    end
end